﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Packaging;
using System.Windows.Xps.Packaging;
using System.Windows.Documents;
using System.IO;
using System.Windows.Xps.Serialization;

namespace SDF
{
    // Sources: http://khason.net/blog/printing-more-then-one-page-creation-in-memory-xps-document-and-documentviewer-customization/
    //          http://www.codeproject.com/KB/WPF/PimpedDocumentPaginator.aspx
    //          http://blogs.msdn.com/b/fyuan/archive/2007/03/10/convert-xaml-flow-document-to-xps-with-style-multiple-page-page-size-header-margin.aspx

    public class XpsDocumentWrapper : IDisposable, IDocumentPaginatorSource
    {
        #region Constructor

        public XpsDocumentWrapper(DocumentPaginator paginator, Stream stream)
        {
            Stream = stream;
            Package = Package.Open(Stream, FileMode.Create, FileAccess.ReadWrite);

            string pack = string.Format("pack://XpsDocumentWrapper.{0}.xps", Guid.NewGuid().ToString());
            PackageStore.AddPackage(new Uri(pack), Package); 
            InnerDocument = new XpsDocument(Package, CompressionOption.SuperFast, pack);

            XpsSerializationManager rsm = new XpsSerializationManager(new XpsPackagingPolicy(InnerDocument), false);
            rsm.SaveAsXaml(paginator);
            rsm.Commit();
        }

        public XpsDocumentWrapper(DocumentPaginator paginator)
            : this(paginator, new MemoryStream())
        {
        }

        public XpsDocumentWrapper(DocumentPaginator paginator, string path)
            : this(paginator, File.Open(path, FileMode.CreateNew))
        {
        }

        public XpsDocumentWrapper(FlowDocument document):
            this(((IDocumentPaginatorSource)document).DocumentPaginator)
        {
        }

        #endregion

        #region Properties

        protected Stream Stream { get; private set; }

        protected Package Package { get; private set; }

        protected XpsDocument InnerDocument { get; private set; }

        public FixedDocumentSequence FixedDocumentSequence
        {
            get 
            {
                if (InnerDocument == null)
                    return null;

                return InnerDocument.GetFixedDocumentSequence();
            }
        }

        public DocumentPaginator DocumentPaginator
        {
            get
            {
                if (InnerDocument == null)
                    return null;

                return FixedDocumentSequence.DocumentPaginator;
            }
        }

        #endregion

        #region IDisposable Implementation

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool isDisposing)
        {
            if (!IsDisposed && isDisposing)
            {
                InnerDocument.Close();

                Package.Close();
                Package = null;

                Stream.Dispose();
                Stream = null;

                IsDisposed = true;
            }
        }

        private bool IsDisposed;

        #endregion
    }
}
